/**
 * @scope enchant.JGZ.SpriteEx.prototype
 * 基本的にアニメーション等を実装
 */
enchant.JGZ.SpriteEx = enchant.Class.create(enchant.Sprite, {
  /**
   * Spriteの拡張実装
   * アニメーション等を行えるようにする
   * @constructs
   * @param {Number} w width
   * @param {Number} w height
   */
  initialize : function(w, h) {
    Sprite.call(this, w, h);
    this._Queue       = [];
    this._QueueParams = [];
    this._QueueAll    = false;
  },

  /**
   * オブジェクト衝突時の進行方向を計算
   */
  mathMovement : function(target) {
    var that = this;
    var cx = that.cx;
    var cy = that.cy;

    //左上に衝突
    if ((target.x) < (that.x + cx) &&
        (target.y + cy) < (that.y + cy) &&
        that.angle === true) {
      return {
        "mx" : target.speed * -1,
        "my" : target.speed * -1
      };
    }

    //右上に衝突
    if ((target.x + cx) > (that.x + that.width - cx) &&
        (target.y + cy) < (that.y + cy) &&
        that.angle === true) {
      return {
        "mx" : target.speed * 1,
        "my" : target.speed * -1
      };
    }

    //左下に衝突
    if ((target.x) < (that.x + cx) &&
        (target.y - cy) > (that.y + cy) &&
        that.angle === true) {
      return {
        "mx" : target.speed * -1,
        "my" : target.speed * 1
      };
    }

    //右下に衝突
    if ((target.x + cx) > (that.x + that.width - cx) &&
        (target.y - cy) > (that.y + cy) &&
        that.angle === true) {
      return {
        "mx" : target.speed * 1,
        "my" : target.speed * 1
      };
    }

    //左に衝突
    if ((target.x) < (that.x + cx) && 
        ((target.y + (target.radius / 2))) > that.y &&
        ((target.y + (target.radius / 2))) < (that.y + that.height)) {
      return {
        "mx" : target.speed * -1,
        "my" : target.speed * (target.my < 1 ? -1 : 1)
      };
    }

    //右に衝突
    if ((target.x + cx) > (that.x + that.width - cx) &&
        ((target.y + (target.radius / 2))) > that.y &&
        ((target.y + (target.radius / 2))) < (that.y + that.height)) {
      return {
        "mx" : target.speed * 1,
        "my" : target.speed * (target.my < 1 ? -1 : 1)
      };
    }

    //上に衝突
    if ((target.y) < (that.y + cy)) {
      return {
        "mx" : target.speed * (target.mx < 1 ? -1 : 1),
        "my" : target.speed * -1
      };
    }

    //下に衝突
    if ((target.y - cy) > (that.y + cy)) {
      return {
        "mx" : target.speed * (target.mx < 1 ? -1 : 1),
        "my" : target.speed * 1
      };
    }

    return false;

  },
  
  /**
   * テキストを画像に重ねる
   */
  text : {
    get: function() {
    },
    /**
     * @param {Object} opt {font: フォント, color: カラー, x: X座標, y: Y座標}
     */
    set: function(opt) {
      if (this._o === undefined) {
        this._o = function(obj) {
          var f = function() {};
          f.prototype = obj;
          return new f();
        }(this.image);
      }

      var s = new enchant.Surface(this.width, this.height);
      s.draw(this._o);
      s.context.font        = opt.font !== undefined ? opt.font : '12px Arial';
      s.context.strokeStyle = opt.color !== undefined ? opt.color : '#000000';
      s.context.strokeText(opt.text, opt.x, opt.y);
      this.image = s;
    }
  },
  /**
   * キューにアニメーションを追加する
   */
  addQueue: function(func) {
    this._QueueAll = false;
    this._Queue.push(func);
  },
  /**
   * キューを実行する
   */
  runQueue: function() {
    var i     = this._Queue.length;
    var func  = this._Queue.pop();

    if (func !== undefined) {
      eval("this." + func + "()");
    }

    return this;
  },
  /**
   * キューを全て実行する
   */
  runAllQueue: function() {
    var that  = this;
    var len   = this._Queue.length;
    this._QueueAll = true;
    this.runQueue();
  },
  /**
   * 左右に揺れるアニメーション
   * @param {Object} opt {}
   */
  roll: function(opt) {
    var that = this;
    var game = enchant.Game.instance;
    /**
     * アニメーションを行う前のX座標
     * @type {Number}
     */
    this.ox      = this.x;
    /**
     * アニメーションを行う長さ
     * @type {Number}
     */
    this.w       = 0;
    /**
     * フラグ
     * @type {Number}
     */
    this.f       = 1;
    /**
     * オブジェクトのステータス
     * @type {Number}
     */
    this.status  = 0;
    
    var timerID = setInterval(function(){that._roll(timerID)}, 10);

    return this;
  },
  /**
   * アニメーション本体ロジック
   */
  _roll: function(timerID) {
    var game  = enchant.Game.instance;
    var count = parseInt(game.frame % game.fps);

    if (count != 0) {
      if (this.f >= 1) {
        this.x  = this.ox;
        this.x += 10;
      } else {
        this.x  = this.ox;
        this.x -= 10; 
      }
      this.f = this.f * (-1);
      this.w++;

      if (this.w >= 30) {
        clearInterval(timerID);
        this.x = this.ox;
        if (this._QueueAll) {
          this.runQueue();
        }
      }
    }
  },
  /**
   * 落ちる動作(ブロック)
   * @param {Object}  opt {opt.opacity: (boolean) 透過していくかどうか}
   */
  fall: function(opt) {
    var that        = this;
    this.waitMax    = 0;
    this.waitCount  = 0;
    this.status     = 0;

    var timerID = setInterval(function(){that._fall(timerID, opt)}, 10);

    return this;
  },
  /**
   * 落ちる動作本体ロジック
   */
  _fall: function(timerID, opt) {
    var game        = enchant.Game.instance;
    var scene       = game.currentScene;
    var speed       = 1;
    if (opt !== undefined && opt.speed !== undefined) {
      speed = parseInt(opt.speed);
    }

    var o           = speed / (game.height - this.y);
    var count       = parseInt(game.frame % game.fps);

    if (this.waitCount >= this.waitMax) {
      if (opt !== undefined && opt.opacity === true) {
        this.opacity -= o;
      }
      this.y += speed;
      this.waitCount = 0; 
    } else {
      this.waitCount++; 
    }

    if (this.y >= game.height) {
      clearInterval(timerID);
      scene.removeChild(this);

      if (this._QueueAll) {
        this.runQueue();
      }
    }
        
  },
  /**
   * 爆発するアニメーション
   * @param {Object}  obj {opt.scale: 爆発エフェクトの大きさ　デフォルトは1, opt.sound: (boolean) 音を再生するかどうか デフォルトでは再生する}
   */
  bomb: function(opt) {
    var that        = this;
    var game        = enchant.Game.instance;
    var scene       = game.currentScene;
    this.sound      = game.assets[LIB_SOUND_PATH + 'bomb.wav'];
    this.image      = game.assets[LIB_IMAGE_PATH + 'bomb.png'];
    this.width      = 16;
    this.height     = 16;
    this.scaleX     = this.scaleY = (opt !== undefined) ? opt.scale : 1;
    this.waitMax    = 0;
    this.waitCount  = 0;
    this.bombMax    = 0;
    this.bombCount  = 0;
    this.status     = 0;
    this.addEventListener(enchant.Event.ENTER_FRAME, function(){
      switch (this.status) {
      case 0: 
        if (this.waitCount >= this.waitMax) {
          this.frame++;
          this.waitCount = 0; 
        } else {
          this.waitCount++; 
        }

        if (this.frame >= 5) {
          this.bombCount++; 
        }
        if (this.bombCount >= this.bombMax) {
          if (opt === undefined || opt.sound === true) {
            this.sound.play();
          }
          this.status = 1; 
        }
        break;
      case 1:
        this.visible = false;
        scene.removeChild(this);
        break;
      }
    });
    return this;
  },
  /**
   * 回転するような動作（カードとか）
   * @param {Object} opt , opt.scaleX: アニメーション後scaleXを変更する場合{opt.frame: アニメーション後フレームを変更する場合はフレームの番号, opt.scaleY: アニメーション後scaleYを変更する場合}
   */
  turn: function(opt) {
    var that      = this;
    var game      = enchant.Game.instance;
    var scene     = game.currentScene;
    scene.flip    = 0;
    scene.status  = 0;
    scene.addEventListener(enchant.Event.ENTER_FRAME, function(){
      switch (this.status) {
        case 0:
          if (this.flip < 3) {
            that.scaleX += 0.5 * (Math.floor(this.flip /2) * 2 - 1);
            this.flip = 0;
            this.status = 1;
          }
          this.flip++;
          break;
        case 1:
          that.scaleX = opt.scaleX === undefined ? 1 : opt.scaleX;
          that.scaleY = opt.scaleY === undefined ? 1 : opt.scaleY;
          that.frame = opt.frame === undefined ? 1 : opt.frame;
          break;
      }
    });
    return this;
  },
});
